/**
 * The contents of this file are subject to the license and copyright detailed in the LICENSE and NOTICE files at the root of the source tree and available online at
 * http://www.askosi.org/license.html
 */
package be.destin.skos.core;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.log4j.Logger;

import be.destin.rdf.changes.ChangeManager;
import be.destin.skos.html.LocalError;
import be.destin.skos.html.SkosHtmlManager;
import be.destin.util.RunCommand;
import be.destin.util.Util;

/**
 * @author Christophe Dupriez
 * 
 */
public class SchemeFactory {

	/** log4j category */
	static Logger log = Logger.getLogger(SchemeFactory.class);
	
	public static final String configExtension = ".cfg";

	protected static final String titleRoot = "title"; // Root of configuration
	protected static final String descriptionRoot = "description"; // Descriptive note
	protected static final String creatorRoot = "creator"; // Descriptive note
	protected static final String contributorRoot = "contributor"; // Descriptive note
	protected static final String rightsRoot = "rights"; // Root of configuration
	// name for the Names of the Authority in each supported language
	protected static final String helpRoot = "help"; // Root of configuration
	// name for the URL to an help page for the Authority in each supported language
	protected static final String displayRoot = "display"; // Root of configuration for display URL
	protected static final String createRoot = "create"; // Root of configuration for creation URL
	protected static final String iconRoot = "icon"; // Root of configuration for icon URL
	protected static final String notationRoot = "notation."; // Root of configuration for SQL query for notations of concepts
	protected static final String notationSearchRoot = "notation.find."; // Root of configuration for SQL query for concepts of notations
	protected static final String searchUrlRoot = "searchURL."; // Root of configuration
	protected static final String harvestConditionRoot = "harvestCondition."; // Root of configuration
	protected static final String harvestUrlRoot = "harvestURL."; // Root of configuration
	protected static final String harvestFailureRoot = "harvestFailure."; // Regular expression to catch a failure
	protected static final String harvestCountRoot = "harvestCount."; // Regular expression to catch a Harvest result size
	protected static final String atomUrlRoot = "atomURL."; // Root of configuration

	protected static final String schemaOrgParam = "schema.org"; // Root of configuration

	private String prefixToRemove;
	private String defaultScheme;
	private SchemeFactoryType sourceType; // SQL, XML, TAB
	private Map<String, String> notationsDefinitions = new ConcurrentHashMap<String, String>();
	private Map<String, String> notationsSearchDefinitions = new ConcurrentHashMap<String, String>();
	private Map<String, NotationScheme> notations = new ConcurrentHashMap<String, NotationScheme>();
	// code, indexKey
	private SchemeInterface aScheme;
	private SkosManager skosManager;
	private String configFile;

	public SchemeFactory (SkosManager managerInstance) {
		super();
		skosManager = managerInstance;
	}

	private final static String[] possibleExtensions = new String[]{configExtension,".xml",".skos",".rdf"};
	
	public static Properties readPropertyFile(String configFile) {
		Properties properties = null;
		FileInputStream is = null;
		InputStreamReader reader = null;
		try {
			is = new FileInputStream(configFile);
			properties = new Properties();
			reader = new InputStreamReader(is,"UTF-8");
			properties.load(reader);
		} catch (FileNotFoundException e) {
			log.error(e.toString()+": "+configFile);
		} catch (IOException e) {
			log.error(e.toString()+": "+configFile);
		} finally {
			RunCommand.closeAble(reader,"reader for Property file "+configFile);
			RunCommand.closeAble(is,"read stream for Property file "+configFile);
		}
		return properties;
	}
	
	private Properties loadConfigFile(String configDir, String schemeCode) {
		Properties properties = null;
		FileInputStream is = null;
		InputStreamReader reader = null;
		for (String anExtension : possibleExtensions) {
			configFile = configDir+schemeCode+anExtension;
			log.debug("Load "+configFile);
			try {
				is = new FileInputStream(configFile);
				properties = new Properties();
				properties.put("scheme", schemeCode);
				if (anExtension.equals(configExtension)) {
					reader = new InputStreamReader(is,"UTF-8");
					properties.load(reader);
				} else {
					properties = new Properties();
					properties.put("type", anExtension.substring(1));
				}
			} catch (FileNotFoundException e) {
				log.error(e.toString()+": "+configDir+", "+schemeCode+": "+configFile);
				properties = null;
			} catch (IOException e) {
				log.error(e.toString()+": "+configDir+", "+schemeCode+": "+configFile);
				properties = null;
			} finally {
				RunCommand.closeAble(reader,"reader for Scheme file "+configFile);
				RunCommand.closeAble(is,"read stream for Scheme file "+configFile);
			}
			if (properties != null) break;
		}
		return properties;
	}
	
	private Properties loadConfigProperties(String schemeCode, Date lastLoaded) {
		String configDir = skosManager.getConfigDirectory();
		Properties properties = loadConfigFile(configDir,schemeCode);
		if (properties == null) return null;

		String primary = properties.getProperty("notationOf");
		if (primary != null && primary.length() > 0) {
			properties = loadConfigFile(configDir,primary);
		}
		return properties;
	}
	
	private NotationScheme putNotation (String indexCode) {
		SchemeInterface newScheme = skosManager.getScheme(indexCode);
		if (newScheme == null) {
			log.debug("New notation "+indexCode);
			NotationScheme subList = new NotationScheme(skosManager, indexCode, (ConceptScheme) aScheme);
			notations.put(indexCode, subList);
			return subList;
		}
		else if (newScheme instanceof NotationScheme) {
			// all right!
			notations.put(indexCode, (NotationScheme)newScheme);
			return (NotationScheme)newScheme;
		}
		else {
			String message = indexCode + " is NOT a Notation Scheme!";
			log.error(message);
			newScheme.getErrors().add(message);
			return null;
		}
	}

	private void readConfigProperties(Properties properties, String schemeCode) {
		prefixToRemove = properties.getProperty("prefix");
		if (aScheme instanceof ConceptScheme) {
			((ConceptScheme)aScheme).setPrefixToRemove(prefixToRemove);
		}

		aScheme.setInternalNote(properties.getProperty("internalNote"));
		aScheme.setSchemaOrg(properties.getProperty(schemaOrgParam));
		aScheme.setNamespace(Url.getConfigURL(properties, "namespace"));
		aScheme.setUri(Url.getConfigURL(properties, "uri"));

		defaultScheme = properties.getProperty("default");
		if (defaultScheme == null || defaultScheme.length() == 0) {
			defaultScheme = schemeCode + SchemeInterface.separator; // Default Prefix for code
		} else {
			if (sourceType == SchemeFactoryType.SELECTION){
				((CollectionScheme)aScheme).setDefaultScheme(defaultScheme);
			}
		}

		String label = properties.getProperty(titleRoot);
		if (label != null && !label.isEmpty()) {
			aScheme.putTitle(label, null, TermList.anyLanguage, null/*Status*/);
		}
		label = properties.getProperty(descriptionRoot);
		if (label != null && !label.isEmpty()) {
			aScheme.putDescription(label, null, TermList.anyLanguage, null/*Status*/);
		}
		label = properties.getProperty(rightsRoot);
		if (label != null && !label.isEmpty()) {
			aScheme.putRights(label, null, TermList.anyLanguage, null/*Status*/);
		}
		label = properties.getProperty(helpRoot);
		if (label != null && !label.isEmpty()) {
			aScheme.putHelp(label, TermList.anyLanguage);
		}
		label = properties.getProperty(displayRoot);
		if (label != null && !label.isEmpty()) {
			aScheme.putDisplay(label, TermList.anyLanguage);
		}
		label = properties.getProperty(iconRoot);
		if (label != null && !label.isEmpty()) {
			aScheme.putIcon(label, TermList.anyLanguage);
		}

		
		Enumeration<String> props = (Enumeration<String>) properties.propertyNames();

		String aProp = null;
		while (props.hasMoreElements()) {
			aProp = (String) props.nextElement();
			if (aProp.startsWith(titleRoot + "-"))
				aScheme.putTitle(properties.getProperty(aProp), null, aProp.substring(titleRoot.length() + 1), null/*Status*/);
			else if (aProp.startsWith(descriptionRoot + "-"))
				aScheme.putDescription(properties.getProperty(aProp), null, aProp.substring(descriptionRoot.length() + 1), null/*Status*/);
			else if (aProp.startsWith(rightsRoot + "-"))
				aScheme.putRights(properties.getProperty(aProp), null, aProp.substring(rightsRoot.length() + 1), null/*Status*/);
			else if (aProp.startsWith(creatorRoot))
				aScheme.addCreator((String)properties.getProperty(aProp));
			else if (aProp.startsWith(contributorRoot))
				aScheme.addContributor(properties.getProperty(aProp));
			else if (aProp.startsWith(helpRoot + "-"))
				aScheme.putHelp(Url.getConfigURL(properties, aProp), aProp.substring(helpRoot.length() + 1));
			else if (aProp.startsWith(displayRoot + "-"))
				aScheme.putDisplay(Url.getConfigURL(properties, aProp), aProp
						.substring(displayRoot.length() + 1));
			else if (aProp.startsWith(createRoot + "-"))
				aScheme.putCreate(Url.getConfigURL(properties, aProp), aProp
						.substring(createRoot.length() + 1));
			else if (aProp.startsWith(SchemeFactory.iconRoot + "-"))
				aScheme.putIcon(Url.getConfigURL(properties, aProp), aProp
						.substring(SchemeFactory.iconRoot.length() + 1));
			else if (aProp.startsWith(notationSearchRoot)) {
				String indexCode = aProp.substring(notationSearchRoot.length());
				notationsSearchDefinitions.put(indexCode, properties.getProperty(aProp));
				putNotation(indexCode);
			}
			else if (aProp.startsWith(notationRoot+searchUrlRoot)) {
				String indexCode = aProp.substring(notationRoot.length()+searchUrlRoot.length());
				String[] codes = indexCode.split("\\.");
				if (codes.length < 3) log.error(aProp+"is not notation.searchURL.notationAbout.applicationAbout.roleAbout");
				else {
					NotationScheme aNotationScheme = putNotation(codes[0]);
					if (aNotationScheme != null) {
						SchemeUsage usage = aNotationScheme.getUsage(codes[1],codes[2]);
						usage.setSearchURL(properties.getProperty(aProp));
					}
				}
			}
			else if (aProp.startsWith(notationRoot+atomUrlRoot)) {
				String indexCode = aProp.substring(notationRoot.length()+atomUrlRoot.length());
				String[] codes = indexCode.split("\\.");
				if (codes.length < 3) log.error(aProp+"is not notation.atomURL.notationAbout.applicationAbout.roleAbout");
				else {
					NotationScheme aNotationScheme = putNotation(codes[0]);
					if (aNotationScheme != null) {
						SchemeUsage usage = aNotationScheme.getUsage(codes[1],codes[2]);
						usage.setAtomURL(properties.getProperty(aProp));
					}
				}
			}
			else if (aProp.startsWith(notationRoot+harvestUrlRoot)) {
				String indexCode = aProp.substring(notationRoot.length()+harvestUrlRoot.length());
				String[] codes = indexCode.split("\\.");
				if (codes.length < 3) log.error(aProp+"is not notation.harvestURL.notationAbout.applicationAbout.roleAbout");
				else {
					NotationScheme aNotationScheme = putNotation(codes[0]);
					if (aNotationScheme != null) {
						SchemeUsage usage = aNotationScheme.getUsage(codes[1],codes[2]);
						usage.setHarvestURL(properties.getProperty(aProp));
					}
				}
			}
			else if (aProp.startsWith(notationRoot+harvestConditionRoot)) {
				String indexCode = aProp.substring(notationRoot.length()+harvestConditionRoot.length());
				String[] codes = indexCode.split("\\.");
				if (codes.length < 3) log.error(aProp+"is not notation.harvestCondition.notationAbout.applicationAbout.roleAbout");
				else {
					NotationScheme aNotationScheme = putNotation(codes[0]);
					if (aNotationScheme != null) {
						SchemeUsage usage = aNotationScheme.getUsage(codes[1],codes[2]);
						usage.setHarvestCondition(properties.getProperty(aProp));
					}
				}
			}
			else if (aProp.startsWith(notationRoot+harvestFailureRoot)) {
				String indexCode = aProp.substring(notationRoot.length()+harvestFailureRoot.length());
				String[] codes = indexCode.split("\\.");
				if (codes.length < 3) log.error(aProp+"is not notation.harvestFailure.notationAbout.applicationAbout.roleAbout");
				else {
					NotationScheme aNotationScheme = putNotation(codes[0]);
					if (aNotationScheme != null) {
						SchemeUsage usage = aNotationScheme.getUsage(codes[1],codes[2]);
						usage.setHarvestFailure(properties.getProperty(aProp));
					}
				}
			}
			else if (aProp.startsWith(notationRoot+harvestCountRoot)) {
				String indexCode = aProp.substring(notationRoot.length()+harvestCountRoot.length());
				String[] codes = indexCode.split("\\.");
				if (codes.length < 3) log.error(aProp+"is not notation.harvestCount.notationAbout.applicationAbout.roleAbout");
				else {
					NotationScheme aNotationScheme = putNotation(codes[0]);
					if (aNotationScheme != null) {
						SchemeUsage usage = aNotationScheme.getUsage(codes[1],codes[2]);
						usage.setHarvestCount(properties.getProperty(aProp));
					}
				}
			}
			else if (aProp.startsWith(notationRoot)) {
				String indexCode = aProp.substring(notationRoot.length());
				notationsDefinitions.put(indexCode, properties.getProperty(aProp));
				putNotation(indexCode);
			}
			else if (aProp.startsWith(searchUrlRoot) && aScheme instanceof ConceptScheme) {
				String indexCode = aProp.substring(searchUrlRoot.length());
				String[] codes = indexCode.split("\\.");
				SchemeUsage usage = ((ConceptScheme)aScheme).getUsage(codes[0], codes[1]);
				usage.setSearchURL(properties.getProperty(aProp));
			}
			else if (aProp.startsWith(atomUrlRoot) && aScheme instanceof ConceptScheme) {
				String indexCode = aProp.substring(atomUrlRoot.length());
				String[] codes = indexCode.split("\\.");
				if (codes.length < 2) log.error(aProp+"is not atomURL.applicationAbout.roleAbout");
				else {
					SchemeUsage usage = ((ConceptScheme)aScheme).getUsage(codes[0], codes[1]);
					usage.setAtomURL(properties.getProperty(aProp));
				}
			}
			else if (aProp.startsWith(harvestUrlRoot) && aScheme instanceof ConceptScheme) {
				String indexCode = aProp.substring(harvestUrlRoot.length());
				String[] codes = indexCode.split("\\.");
				if (codes.length < 2) log.error(aProp+"is not harvestURL.applicationAbout.roleAbout");
				else {
					SchemeUsage usage = ((ConceptScheme)aScheme).getUsage(codes[0], codes[1]);
					usage.setHarvestURL(properties.getProperty(aProp));
				}
			}
			else if (aProp.startsWith(harvestConditionRoot) && aScheme instanceof ConceptScheme) {
				String indexCode = aProp.substring(harvestConditionRoot.length());
				String[] codes = indexCode.split("\\.");
				if (codes.length < 2) log.error(aProp+"is not harvestCondition.applicationAbout.roleAbout");
				else {
					SchemeUsage usage = ((ConceptScheme)aScheme).getUsage(codes[0], codes[1]);
					usage.setHarvestCondition(properties.getProperty(aProp));
				}
			}
			else if (aProp.startsWith(harvestFailureRoot) && aScheme instanceof ConceptScheme) {
				String indexCode = aProp.substring(harvestFailureRoot.length());
				String[] codes = indexCode.split("\\.");
				if (codes.length < 2) log.error(aProp+"is not harvestFailure.applicationAbout.roleAbout");
				else {
					SchemeUsage usage = ((ConceptScheme)aScheme).getUsage(codes[0], codes[1]);
					usage.setHarvestFailure(properties.getProperty(aProp));
				}
			}
			else if (aProp.startsWith(harvestCountRoot) && aScheme instanceof ConceptScheme) {
				String indexCode = aProp.substring(harvestCountRoot.length());
				String[] codes = indexCode.split("\\.");
				if (codes.length < 2) log.error(aProp+"is not harvestCount.applicationAbout.roleAbout");
				else {
					SchemeUsage usage = ((ConceptScheme)aScheme).getUsage(codes[0], codes[1]);
					usage.setHarvestCount(properties.getProperty(aProp));
				}
			}
		}

		if (notations != null && aScheme instanceof ConceptScheme) {
			((ConceptScheme)aScheme).setNotation(notations.values());	
		}
	}
	
	private boolean loadSchemeSource(SchemeFactoryType sourceType, Properties properties, boolean reload) {
		log.debug("Source type="+sourceType.name());
		aScheme.setMemorySpace(false);
		aScheme.setLoadTime(false);
		switch (sourceType) {
		case METASCHEME: { // The MetaScheme scheme is filled with concepts based on existing schemes
			break;
		}
		case SQL: {
			SqlSource.load(properties, (ConceptScheme)aScheme, configFile, notationsDefinitions, reload);
			break;
		}
		case DYNSQL: {
			((DynamicScheme)aScheme).initSQL(properties, configFile,notationsDefinitions,notationsSearchDefinitions);
			break;
		}
		case SPARQL: {
			SparqlSource.load(properties, (ConceptScheme)aScheme, configFile, notationsDefinitions);
			break;
		}
/* NOT IMPLEMENTED FOR NOW...
		case DYNSPARQL: {
			((DynamicScheme)aScheme).initSPARQL(properties, configFile,notationsDefinitions,notationsSearchDefinitions);
			break;
		}
*/
		case XML: {
			// The XML unmarshalling is always creating: loadXML must carefully merge this new Scheme within the existing one.
			XmlSource.load(skosManager, sourceType, (ConceptScheme)aScheme, properties, configFile, reload);
			break;
		}
		case RDF: {
			// The XML unmarshalling is always creating: loadXML must carefully merge this new Scheme within the existing one.
			XmlSource.load(skosManager, sourceType, (ConceptScheme)aScheme, properties, configFile, reload);
			break;
		}
		case SKOS: {
			// The XML unmarshalling is always creating: loadXML must carefully merge this new Scheme within the existing one.
			XmlSource.load(skosManager, sourceType, (ConceptScheme)aScheme, properties, configFile, reload);
			break;
		}
		case TAB: {
			TabSource.load((ConceptScheme)aScheme, properties, configFile, notationsDefinitions);
			break;
		}
		case ENUM: {
			EnumSource.load((ConceptScheme)aScheme, properties, configFile, notationsDefinitions);
			break;
		}
		case FILES: {
			FilesSource.load((ConceptScheme)aScheme, properties, configFile, notationsDefinitions);
			break;
		}
		case BUNDLE: {
			BundleSource.load((ConceptScheme)aScheme, properties, configFile, notationsDefinitions,skosManager);
			break;
		}
		case SELECTION: {
			String selection = properties.getProperty("selection");
			if (selection == null || selection.length()==0) {
				String message = configFile+": A selection=... with concepts codes must be specified.";
				log.error(message);
				aScheme.getErrors().add(message);
			}
			LinkedList<Concept> newCollectionContent = new LinkedList<Concept>();
			StringTokenizer st = new StringTokenizer(selection,";\n, ",false);
			while (st.hasMoreTokens()) {
				String currCode = st.nextToken();
				Concept aConcept = skosManager.getScheme_Concept(currCode, defaultScheme);
				if (aConcept != null) {
					newCollectionContent.add(aConcept);
				}
			}
			((CollectionScheme)aScheme).setConcept(newCollectionContent);
			break;
		}
		default: {
			String message = configFile+": Source type must be "
			+SchemeFactoryType.list()
			+". For instance: type=SQL";
			log.error(message);
			aScheme.getErrors().add(message);
			return false;
			// break;
		}
		}

		String rootFileName = configFile;
		if (rootFileName.endsWith(SchemeFactory.configExtension))
			rootFileName = configFile.substring(0,configFile.length()-SchemeFactory.configExtension.length());

		String translations = properties.getProperty("translations");
		if (translations != null) {
			StringTokenizer st = new StringTokenizer(translations,";\n, ");
			while (st.hasMoreElements()) {
				String token = st.nextToken();
				if (token.isEmpty()) continue;
				TabSource.readTriplesTable((ConceptScheme)aScheme, rootFileName, "prefLabel", token, false);
			}
		}

		translations = properties.getProperty("triples");
		if (translations != null) {
			StringTokenizer st = new StringTokenizer(translations,";\n, ");
			while (st.hasMoreElements()) {
				String token = st.nextToken();
				if (token.isEmpty()) continue;
				TabSource.readTriplesTable((ConceptScheme)aScheme, rootFileName, token, null, true);
			}
		}

		ChangeManager changeManager = this.skosManager.getChangeManager();
		if (changeManager != null) {
			long mergeSize = changeManager.mergeRdfStatements(aScheme);
			if (mergeSize > 0) {
				LocalError errors = aScheme.getErrors();
				errors.add(mergeSize+" changes merged.");
			}
		}
		aScheme.preLoadFinished();
		if (aScheme instanceof ConceptScheme) {
			((ConceptScheme)aScheme).getStatusFilter().filter();
		}
		aScheme.setLastLoaded(null);
		aScheme.setLoadTime(true);
		aScheme.setMemorySpace(true);
		// Usages are loaded whenever an Application definition is loaded (Application.loadUsages())
		return true;
	}

	public boolean reloadConfig(String schemeCode) {

		aScheme = skosManager.getScheme(schemeCode);
		if (aScheme == null || aScheme.getClass() == NoScheme.class ) {
			return loadConfig(schemeCode);
		}

		Properties properties = loadConfigProperties (schemeCode, aScheme.getLastLoaded());
		if (properties == null) return false;

		schemeCode = properties.getProperty("scheme",schemeCode);
		String sourceTypeName = properties.getProperty("type");
		if (SkosManager.aboutMetaScheme.equals(schemeCode)) {
			sourceType = SchemeFactoryType.METASCHEME;		
			aScheme = skosManager.getMetaScheme();
		} else {
			if (sourceTypeName == null || sourceTypeName.length() < 3) {
				log.error(configFile
						+ ": no source type specified in configuration ("
						+SchemeFactoryType.list()
						+")");
				return false;
			}
			sourceType = SchemeFactoryType.valueOf(sourceTypeName.toUpperCase());
			if (sourceTypeName.substring(0,3).equalsIgnoreCase("Dyn")) {
				int cacheSize = Util.string2int(properties.getProperty("cache"),500);
				if ( ! (aScheme instanceof DynamicScheme) ) {
					log.error(configFile
							+ " is not a DynamicScheme anymore?");
					return false;

				} else {
					((DynamicScheme)aScheme).setRenewedCacheSize(cacheSize); /* Clear the cache! */
				}
			}
			else if (sourceType == SchemeFactoryType.SELECTION) {
				if ( ! (aScheme instanceof CollectionScheme) ) {
					log.error(configFile
							+ " is not a Selection (collection) anymore?");
					return false;
				}
			}
			else {
				if ( ! (aScheme instanceof ConceptScheme) ) {
					log.error(configFile
							+ " is not a ConceptScheme anymore?");
					return false;
				}
			}
		}

		readConfigProperties(properties, schemeCode);
		return loadSchemeSource(sourceType, properties, true);
	}

	public boolean loadConfig(String schemeCode) {

		Properties properties = loadConfigProperties (schemeCode, new Date(0)/*not loaded*/);
		if (properties == null) return false;

		schemeCode = properties.getProperty("scheme",schemeCode);
		String sourceTypeName = properties.getProperty("type");
		if (SkosManager.aboutMetaScheme.equals(schemeCode)) {
			sourceType = SchemeFactoryType.METASCHEME;
			aScheme = skosManager.getMetaScheme();
		} else {
			if (sourceTypeName == null || sourceTypeName.length() < 3) {
				log.error(configFile
						+ ": no source type specified in configuration ("
						+SchemeFactoryType.list()
						+")");
				return false;
			}
			sourceType = SchemeFactoryType.valueOf(sourceTypeName.toUpperCase());
			if (sourceTypeName.substring(0,3).equalsIgnoreCase("Dyn")) {
				int cacheSize = Util.string2int(properties.getProperty("cache"),500);
				aScheme = new DynamicScheme(skosManager, schemeCode, cacheSize);
			}
			else if (sourceType == SchemeFactoryType.SELECTION) {
				aScheme = new CollectionScheme(skosManager, schemeCode);
			}
			else aScheme = new ConceptScheme(skosManager, schemeCode);
		}

		String schemeApplication = properties.getProperty("application",SkosHtmlManager.askosiDisplayApplication);
		aScheme.setApplication(schemeApplication);

		readConfigProperties(properties, schemeCode);

		return loadSchemeSource(sourceType, properties, false);
	}
}
